package pl.edu.agh.neuraleconomy.core.ta.indicator;

import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import org.apache.commons.math3.stat.descriptive.moment.Mean;

import pl.edu.agh.neuraleconomy.core.nn.CoreUtils;
import pl.edu.agh.neuraleconomy.model.exchange.Exchange;

public class EMACalculator implements ICalculator {
	private int period;

	public EMACalculator(int period) {
		this.period = period;
	}

	public Map<Date, Double> calculate(List<Exchange> exchanges) {
		double [] EMA = calculate(CoreUtils.toDoubleArray(exchanges));
		
		Map<Date, Double> res = new HashMap<Date, Double>();
		
		for(int i=0; i<EMA.length;i++){
			res.put(exchanges.get(i+period).getDate(), Double.valueOf(EMA[i]));
		}
		
		return res;
	}

	public double[] calculate(double[] data) {
		validate(data);

		double[] head = Arrays.copyOf(data, period);

		double MA = MA(head);
		double K = K(period);

		double[] tail = Arrays.copyOfRange(data, period, data.length);
		double[] res = new double[tail.length];

		res[0] = EMA(MA, tail[0], K);

		for (int i = 1; i < tail.length; i++) {
			res[i] = EMA(res[i - 1], tail[i], K);
		}

		return res;
	}

	public int getInputLenForOutputLen(int outputLen) {
		return outputLen + period;
	}

	private double MA(double[] head) {
		Mean mean = new Mean();
		return mean.evaluate(head);
	}

	private double EMA(double recentEMA, double todaysPrice, double K) {
		return todaysPrice * K + recentEMA * (1 - K);
	}

	private double K(int period) {
		return 2 / ((double)period + 1);
	}

	private void validate(double[] data) {
		if (data.length <= period) {
			throw new IllegalArgumentException("Input to short for EMA. Period = " + period + ", input length = " + data.length);
		}
	}

}
